package org.youchan.aco.p2p;

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

import org.youchan.util.Message;

import com.skype.Application;
import com.skype.ApplicationListener;
import com.skype.Friend;
import com.skype.Skype;
import com.skype.SkypeException;
import com.skype.Stream;
import com.skype.StreamListener;

public class A2AManager {
	private static A2AManager self_;
	
	private static final String APPLICATION_NAME = "ACO";
	
	private Application mApplication;
	private AcoApplicationListener mApplicationListener;
	private AcoStreamListener mStreamListener;
	private List<A2AManagerListener> mListeners;
	
	private A2AManager() {
		mListeners = new ArrayList<A2AManagerListener>();
		setup();
	}
	
	public static A2AManager getInstance() {
		if (self_ == null) {
			self_ = new A2AManager();
		}
		return self_;
	}
	
	private void setup() {
		try {
			mApplication = Skype.addApplication(APPLICATION_NAME);
			mApplicationListener = new AcoApplicationListener();
			mStreamListener = new AcoStreamListener();
			mApplication.addApplicationListener(mApplicationListener);
		} catch (SkypeException e) {
			e.printStackTrace();
		}
	}
	
	public void connectToAll() throws SkypeException {
		Friend[] friends = mApplication.getAllConnectableFriends();
		for (int i = 0; i < friends.length; i ++) {
			mApplication.connect(friends[i]);
		}
	}
	
	public Friend[] getConnectableFriend() throws SkypeException {
		return mApplication.getAllConnectableFriends();
	}
	
	public Friend[] getConnectedFriends() throws SkypeException {
		return mApplication.getAllConnectedFriends();
	}
	
	public void addA2AManagerListener(A2AManagerListener listener) {
		mListeners.add(listener);
	}
	
	public void removeA2AManagerListener(A2AManagerListener listener) {
		mListeners.remove(listener);
	}
	
	public void fireMemberConnected(String memberId) {
		for (ListIterator<A2AManagerListener> it = mListeners.listIterator(); it.hasNext();) {
			it.next().memberConnected(memberId);
		}
	}
	
	public void fireMemberDisconnected(String memberId) {
		for (ListIterator<A2AManagerListener> it = mListeners.listIterator(); it.hasNext();) {
			it.next().memberDisconnected(memberId);
		}
	}
	
	public void sendMessage(String message, String... memberId) {
		System.out.println("sending message: " + message);
		try {
			List<Friend> list = new ArrayList<Friend>();
			for (Friend friend :mApplication.getAllConnectedFriends()) {
				System.out.println("friend id: " + friend.getId());
				for (String id : memberId) {
					if (friend.getId().equals(id)) {
						list.add(friend);
					}
				}
			}
			for (Stream stream :mApplication.getAllStreams(list.toArray(new Friend[0]))) {
				System.out.println("sending to: " + stream.getId());
				stream.addStreamListener(mStreamListener);
				stream.send(message);
			}
		} catch (SkypeException e) {
			e.printStackTrace();
		}
	}
	
	private class AcoApplicationListener implements ApplicationListener {
		
		public AcoApplicationListener() {
			
		}

		public void connected(Stream stream) throws SkypeException {
			stream.addStreamListener(mStreamListener);
			fireMemberConnected(stream.getId());
		}

		public void disconnected(Stream stream) throws SkypeException {
			stream.removeStreamListener(mStreamListener);
			fireMemberDisconnected(stream.getId());
		}
		
	}
	
	private class AcoStreamListener implements StreamListener {
		MessageReader reader = new MessageReader();

		public void datagramReceived(String receivedDatagram) throws SkypeException {
			Message<SessionCommand> message = reader.readMessage(receivedDatagram);
			message.getCommand().setStatus(SessionCommand.Status.RECEIVED);
			SessionManager smgr = SessionManager.getInstance();
			smgr.sendMessage(message);
			if (message.getCommand().type == SessionCommand.Type.SESSION_START) {
				SessionCommand command = new SessionCommand(SessionCommand.Type.GET_FRIENDS_LIST);
				String text = message.getCommand().getValue("text");
				if (text.matches("^@ACO_ ")) {
					command.setStatus(SessionCommand.Status.SEND);
					command.addValue("target", "yoosaki");
					command.setValue("text", "@youchan " + text.substring(6));
					smgr.sendMessage(new Message<SessionCommand>(command));
				}
			}
		}

		public void textReceived(String receivedText) throws SkypeException {
		}
		
	}
	
	public interface A2AManagerListener {
		public void memberConnected(String memberId);
		public void memberDisconnected(String memberId);
	}
}
